﻿#region The MIT License (MIT)
// The MIT License (MIT)
// Copyright (c) 2010 - 2013 Sovacode LLC
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions
// of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion

using System.Windows;
using Sovacode.RubiksCube.Common.Managers.Command;
using Sovacode.RubiksCube.Common.Managers.Settings;
using Sovacode.RubiksCube.Common.Managers.Validation;
using Sovacode.RubiksCube.Common.Service;
using Sovacode.RubiksCube.Common.Service.Empty;
using Sovacode.RubiksCube.Common.Service.Linked;
using Sovacode.RubiksCube.Common.ViewModel;

namespace Sovacode.RubiksCube.Common.View
{
    /// <summary>
    /// Extension class for Window <see cref="Window"/>
    /// </summary>
    public static class WindowExtensions
    {
        #region Window Service

        /// <summary>
        /// Make a simple Window service <see cref="LinkedWindowService"/>
        /// </summary>
        /// <param name="window">Window <see cref="Window"/></param>
        /// <returns>Window Service <see cref="IWindowService"/></returns>
        public static IWindowService MakeWindowService(this Window window)
        {
            return MakeWindowService<LinkedWindowService>(window);
        }

        /// <summary>
        /// Make a empty Window service <see cref="EmptyWindowService"/>
        /// </summary>
        /// <param name="window">Window <see cref="Window"/></param>
        /// <returns>Window Service <see cref="IWindowService"/></returns>
        public static IWindowService MakeEmptyWindowService(this Window window)
        {
            return MakeWindowService<EmptyWindowService>(window);
        }

        /// <summary>
        /// Make a Window service of specific type
        /// </summary>
        /// <typeparam name="T">Specific type</typeparam>
        /// <param name="window">Window <see cref="Window"/></param>
        /// <returns>Window Service <see cref="IWindowService"/></returns>
        public static IWindowService MakeWindowService<T>(this Window window)
            where T : class, IWindowService, new()
        {
            if (window == null)
            {
                return new EmptyWindowService();
            }

            var service = new T();

            if (service is ILinkedWindowService)
            {
                (service as ILinkedWindowService).LinkedWindow = window;
            }

            return service;
        }

        #endregion

        #region Setting Manager

        /// <summary>
        /// Make a Empty Settings Manager <see cref="EmptySettingsManager"/>
        /// </summary>
        /// <param name="window">Window <see cref="Window"/></param>
        /// <returns>Settings Manager <see cref="ISettingsManager"/></returns>
        public static ISettingsManager MakeEmptySettingsManager(this Window window)
        {
            return MakeSettingsManager<EmptySettingsManager>(window);
        }

        /// <summary>
        /// Make a specific type Settings Manager <see cref="ISettingsManager"/>
        /// </summary>
        /// <typeparam name="T">Specific type</typeparam>
        /// <param name="window">Window <see cref="Window"/></param>
        /// <returns>Settings Manager <see cref="ISettingsManager"/></returns>
        public static ISettingsManager MakeSettingsManager<T>(this Window window)
            where T : class, ISettingsManager, new()
        {
            return new T();
        }

        #endregion

        #region Get

        /// <summary>
        /// Get current Validation Manager <see cref="IValidationManager"/> of DataContext
        /// </summary>
        /// <param name="window"><see cref="Window"/></param>
        /// <returns>Validation Manager <see cref="IValidationManager"/></returns>
        public static IValidationManager GetValidationManager(this Window window)
        {
            if (window == null)
            {
                return null;
            }

            var viewModel = DataContextTo<IViewModelTop>(window);

            return viewModel == null ? null : viewModel.ValidationManager;
        }

        /// <summary>
        /// Get current Command Manager <see cref="ICommandManager"/> of DataContext
        /// </summary>
        /// <param name="window"><see cref="Window"/></param>
        /// <returns>Command Manager <see cref="ICommandManager"/></returns>
        public static ICommandManager GetCommandManager(this Window window)
        {
            if (window == null)
            {
                return null;
            }

            var viewModel = DataContextTo<IViewModelTop>(window);

            return viewModel == null ? null : viewModel.CommandManager;
        }

        /// <summary>
        /// Get current Setting Manager <see cref="ISettingsManager"/> of DataContext
        /// </summary>
        /// <param name="window"><see cref="Window"/></param>
        /// <returns>Setting Manager <see cref="ISettingsManager"/></returns>
        public static ISettingsManager GetSettingManager(this Window window)
        {
            if (window == null)
            {
                return new EmptySettingsManager();
            }

            var viewModel = DataContextTo<IViewModelTop>(window);

            return viewModel == null ? new EmptySettingsManager() : viewModel.SettingsManager;
        }

        /// <summary>
        /// Cast DataContext of FrameworkElement <see cref="FrameworkElement"/> to specific type
        /// </summary>
        /// <typeparam name="T">Specific type</typeparam>
        /// <param name="element">Element <see cref="FrameworkElement"/></param>
        /// <returns>DataContext as specific type</returns>
        private static T DataContextTo<T>(FrameworkElement element)
            where T: class 
        {
            if (element == null)
            {
                return default(T);
            }

            return element.DataContext as T;
        }

        #endregion
    }
}